package com.musollo.domain;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Date;

import org.apache.log4j.Logger;

import com.musollo.exceptions.IndexException;
import com.musollo.exceptions.ParseException;
import com.musollo.mp3tools.AbstractMP3Categorizer;
import com.musollo.mp3tools.MP3Updater;
import com.musollo.mp3tools.TagReader;
import com.musollo.mp3tools.TagWriter;

/**
 * This is the indexer class, that creates MP3 objects from actual MP3 files.
 * These MP3 objects are then passed to the MP3Updater which updates the ID3
 * information of the MP3 file. After that, the files can be categorized.
 * 
 * @author paw.janssen
 * 
 */
public class MP3Indexer {

	/**
	 * Filenamefilter that accepts only files with the mp3 extension.
	 * 
	 * @author pascal.janssen
	 * 
	 */
	private static class MP3FileNameFilter implements FilenameFilter {
		@Override
		public boolean accept(final File dir, final String name) {
			LOG.trace("Checking file: " + name);
			if (name.toLowerCase().endsWith(".mp3")) {
				LOG.trace("Found mp3 file: " + name);
				return true;
			} else {
				LOG.trace("A non mp3 file was found: " + name);
				return false;
			}
		}
	}

	private static final Logger LOG = Logger.getLogger(MP3Indexer.class);
	private final File indexDir;
	private final TagReader tagReader;
	private final TagWriter tagWriter;
	private final MP3Updater mp3Updater;
	private final AbstractMP3Categorizer categorizer;

	/**
	 * Start the mp3 indexer with the given configuration parameters.
	 * 
	 * @param indexDir
	 *            - Dir where the MP3 files exist.
	 * @param tagReader
	 *            - A tagreader to read the tags from the MP3 files.
	 * @param tagWriter
	 *            - A tagwriter to write the tags to MP3 files.
	 * @param mp3Updater
	 *            - An updater to lookup song information for a MP3 file.
	 * @param categorizer
	 *            - A categorizer to categorize MP3 files.
	 * @throws IndexException
	 *             - Occurs when something goes wrong while indexing.
	 */
	public MP3Indexer(final File indexDir, final TagReader tagReader, final TagWriter tagWriter,
			final MP3Updater mp3Updater, final AbstractMP3Categorizer categorizer) throws IndexException {
		if (indexDir == null) {
			throw new IndexException(new NullPointerException("Indexdir is null"));
		}
		if (!indexDir.exists()) {
			throw new IndexException("Index dir does not exist");
		}
		if (!indexDir.isDirectory()) {
			throw new IndexException("Index dir is not a directory");
		}

		this.indexDir = indexDir;
		this.tagReader = tagReader;
		this.tagWriter = tagWriter;
		this.mp3Updater = mp3Updater;
		this.categorizer = categorizer;

		this.index();
	}

	private void index() {
		LOG.info("Indexing files in directory " + this.indexDir.getAbsolutePath());

		File[] mp3Files = this.indexDir.listFiles(new MP3FileNameFilter());

		double numFiles = mp3Files.length;
		double percent = 0;
		int count = 0;
		LOG.info("Starting indexing...");
		LOG.info("Num files: " + numFiles);

		long startTime = new Date().getTime();

		for (File mp3 : mp3Files) {
			try {
				LOG.info("Percent ready: " + percent);
				count++;

				MP3 indexedMP3 = tagReader.readMP3(mp3);
				this.mp3Updater.updateMP3(indexedMP3);
				this.tagWriter.writeMP3(indexedMP3);
				this.categorizer.categorizeMP3(indexedMP3);

				percent = (100 / numFiles) * count;
			} catch (FileNotFoundException e) {
				LOG.error("MP3 file " + mp3.getAbsolutePath() + " was deleted during indexing");
			} catch (ParseException e) {
				LOG.error("MP3 file " + mp3.getAbsolutePath() + " couldn't be parsed", e);
			} catch (IOException e) {
				LOG.error("MP3 file " + mp3.getAbsolutePath() + " couldn't be categorized", e);
			}
		}

		long endTime = new Date().getTime();

		long duration = endTime - startTime;

		duration = duration / 1000;

		LOG.info("Percent ready: " + percent);
		LOG.info("Indexing Finished");
		LOG.info("Indexing took: " + duration + " seconds");

	}
}
